package com.sunyard.manage.controller;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.sunyard.constant.ErrMessageConst;
import com.sunyard.dal.bo.org.OrgWorkingTimeBO;
import com.sunyard.dal.bo.org.OrganizationAddBO;
import com.sunyard.dal.bo.org.OrganizationDeleteBO;
import com.sunyard.dal.bo.org.OrganizationQueryBO;
import com.sunyard.dal.bo.org.OrganizationUpdateBO;
import com.sunyard.dal.bo.PaginationBO;
import com.sunyard.dal.bo.org.SysPermissionBo;
import com.sunyard.dal.dto.OrgTreeDTO;
import com.sunyard.dal.dto.OrganizationDTO;
import com.sunyard.dal.dto.SysPermissionDTO;
import com.sunyard.dal.entity.Organization;
import com.sunyard.dal.entity.SysLog;
import com.sunyard.dal.mapper.CityMapper;
import com.sunyard.dal.mapper.OrganizationMapper;
import com.sunyard.dal.mapper.SystemLogMapper;
import com.sunyard.manage.service.OperatorLogService;
import com.sunyard.manage.service.OrganizationService;
import com.sunyard.manage.service.PopedomService;
import com.sunyard.manage.util.ValidatorUtils;
import com.sunyard.redisUtil.RedisUtils;
import com.sunyard.utils.ExcelOutput;
import com.sunyard.utils.Response.BaseResult;
import com.sunyard.utils.Response.GetResult;
import com.sunyard.utils.Response.HeaderResult;
import com.sunyard.utils.TokenUtil;
import com.sunyard.utils.manage.DataGrid;
import com.sunyard.utils.sm2.StringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @author jiy.fang
 * @ClassNameOrganizationController
 * @Description 机构管理控制层
 * @date 2019/7/12 22:02
 */

@Slf4j
@Api(tags = "OrganizationController", description = "机构管理控制器")
@RestController
@RequestMapping(value = "/organization", method = RequestMethod.POST)
public class OrganizationController {

    @Autowired
    private OrganizationService organizationService;

    @Autowired
    private PopedomService popedomService;

    @Autowired
    private CityMapper cityMapper;

    @Autowired
    private OrganizationMapper organizationMapper;

    @Autowired
    private SystemLogMapper systemLogMapper;

    @Autowired
    private OperatorLogService operatorLogService;

    @Autowired
    private RedisUtils redisUtils;


    /**
     * 项目启动时，初始化参数到缓存
     */
    @PostConstruct
    public void initOrg() {

    }

    /**
     * @Description: 机构分页查询
     * @Author: jiy.fang
     * @Date: 2019/7/17 19:40
     */
    @RequestMapping(value = "/queryOrg")
    @ResponseBody
    @ApiOperation("机构查询")
    public BaseResult<DataGrid<OrganizationDTO>> queryOrganization(@RequestBody PaginationBO<OrganizationQueryBO> orginazationQuery,
                                                                   HttpServletRequest request) {
        try {
            return organizationService.querryOrginazitionByPage(orginazationQuery, request);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    /**
     * @Description: 添加机构信息
     * @Author: jiy.fang
     * @Date: 2019/7/19 13:59
     */
    @RequestMapping(value = "/addOrg")
    @ResponseBody
    @ApiOperation("机构添加")
    public BaseResult insertOrganization(HttpServletRequest request, @Valid @RequestBody OrganizationAddBO organizationAddBO) {
        try {
            String orgId = TokenUtil.getOrgId(request.getHeader("token"));
            String opId = TokenUtil.getOpId(request.getHeader("token"));
            String opName = TokenUtil.getOpName(request.getHeader("token"));
            //添加机构时需比对操作员机构,只能添加操作员所属机构的下属机构
            List<String> orgList = getListOrgIds(orgId);
            orgList.add(orgId);
            return organizationService.insertOrganization(request, organizationAddBO, orgId, opId, opName, orgList);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr(e.getMessage());
        }
    }

    /**
     * @Description: 修改机构信息
     * @Author: jiy.fang
     * @Date: 2019/7/19 14:01
     */
    @RequestMapping(value = "/updateOrg")
    @ResponseBody
    @ApiOperation("机构修改")
    public BaseResult updateOrganazation(HttpServletRequest request, @Valid @RequestBody OrganizationUpdateBO organizationUpdateBO) {
        try {
            return organizationService.updateOrganization(request, organizationUpdateBO);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    /**
     * @Description: 删除机构信息
     * @Author: jiy.fang
     * @Date: 2019/7/19 14:01
     */
    @RequestMapping(value = "/deleteOrg")
    @ResponseBody
    @ApiOperation("机构删除")
    public BaseResult deleteOrganization(HttpServletRequest request, @Valid @RequestBody OrganizationDeleteBO organizationDeleteBO) {
        try {
            return organizationService.deleteOrganization(request, organizationDeleteBO);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    /**
     * @Description: 批量删除机构信息
     * @Author: jiy.fang
     * @Date: 2019/7/19 14:01
     */
    @RequestMapping(value = "/batchDeleteOrg")
    @ResponseBody
    @ApiOperation("批量删除机构信息")
    public BaseResult batchDeleteOrg(HttpServletRequest request, @Valid @RequestBody OrganizationDeleteBO organizationDeleteBO) {
        try {
            return organizationService.batchDeleteOrg(request, organizationDeleteBO);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    /**
     * @Description: 获取当前机构及子机构ID
     * @Author: jiy.fang
     * @Date: 2019/7/22 22:48
     */
    @RequestMapping(value = "/getOrgIds")
    @ResponseBody
    @ApiOperation(value = "获取当前机构及子机构ID")
    public BaseResult<List<Organization>> getOrganizationIds(HttpSession session, HttpServletRequest request) {
        try {
            String orgId = TokenUtil.getOrgId(request.getHeader("token"));
            return GetResult.getResult(organizationService.getOrgIds(orgId));
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    /**
     * @Description 获取机构树状结构
     * @Author chengy.wei
     * @Date 2022/07/15 10:00
     **/
    @RequestMapping("/newOrgTree")
    @ResponseBody
    @ApiOperation(value = "获取树状机构")
    public BaseResult<List<OrgTreeDTO>> obtainCurrentOrgAndSubOrg(HttpServletRequest request) {
        try {
            String orgId = TokenUtil.getOrgId(request.getHeader("token"));
            return organizationService.obtainOrgTree(orgId);
        } catch (Exception e) {
            e.printStackTrace();
            return GetResult.getResultErr();
        }
    }

    /**
     * @Description 获取所有机构树状结构
     * @Author chengy.wei
     * @Date 2022/07/15 10:00
     **/
    @RequestMapping("/aLLOrgTree")
    @ResponseBody
    @ApiOperation(value = "获取所有机构树状结构")
    public BaseResult<List<OrgTreeDTO>> getAllOrgTree() {
        try {
            return organizationService.getAllOrgTree();
        } catch (Exception e) {
            e.printStackTrace();
            return GetResult.getResultErr();
        }
    }

    /**
     * @Description: 获取当前机构及上下级机构ID
     * @Author: huix.Liang
     * @Date: 2019-08-06 16:15
     */
    @RequestMapping(value = "/getAllLevelIds")
    @ResponseBody
    @ApiOperation(value = "获取当前机构及上下级机构ID")
    public BaseResult<List<Organization>> getAllLevelIds(HttpServletRequest request) {
        try {
            return GetResult.getResult(organizationService.getAllLevelOrgIds(request));
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    /**
     * @Description: 机构导出
     * @Author: jiy.fang
     * @Date: 2019/7/22 23:20
     */
    @ApiOperation("导出机构信息")
    @ResponseBody
    @RequestMapping(value = "/export")
    public void exportOrganization(@RequestBody PaginationBO<OrganizationQueryBO> queryBO, HttpServletResponse response, HttpServletRequest request) {
        try {
            OrganizationQueryBO organizationQueryBO = queryBO.getParams();
            log.info("机构信息查询入参：{}", JSON.toJSONString(organizationQueryBO));
            String orgId = TokenUtil.getOrgId(request.getHeader("token"));
            String opId = TokenUtil.getOpId(request.getHeader("token"));
            String opName = TokenUtil.getOpName(request.getHeader("token"));
            operatorLogService.insert("用户"+opName+"机构信息导出", "机构导出", "1", opId, opName, orgId);
            if (ObjectUtil.isEmpty(organizationQueryBO.getOrgId())) {
                organizationQueryBO.setOrgId(TokenUtil.getOrgId(request.getHeader("token")));
            }
            Map<String, Object> queryMap = new HashMap<>();
            queryMap.put("orgId", organizationQueryBO.getOrgId());
            queryMap.put("orgName", organizationQueryBO.getOrgName());
            queryMap.put("includeSubOrg", organizationQueryBO.getIncludeSubOrg());
            //获取当前机构及下属机构id集合
            List<String> orgIds = getListOrgIds(organizationQueryBO.getOrgId());
            orgIds.add(organizationQueryBO.getOrgId());
            queryMap.put("list", orgIds);
            //执行查询
            List<OrganizationDTO> orgList = organizationMapper.getListOrganizationDTOByPage(queryMap);
            if (orgList == null || orgList.size() <= 0) {
                throw new RuntimeException("无数据无需导出");
            }
            String title = "机构信息导出" +  ".xls";
            String[] headers = new String[]{"机构名称", "上级机构", "机构级别", "机构码", "机构类型",  "备注"};
            //机构类型 1-网点、2-金库、3-调拨中心、4-押运公司、5-类金库
            String[] orgType = new String[]{"网点", "金库", "调拨中心", "押运公司", "类金库"};
            String[] orgRailSwitch = new String[]{"开", "关"};
            List<Object[]> dataList;
            dataList = orgList.stream().map(organizationDTO -> {
                Object[] obj = new Object[headers.length];
                obj[0] = organizationDTO.getOrgName();
                obj[1] = organizationDTO.getOrgParentName();
                String orgLevel = String.valueOf(organizationDTO.getOrgLevel());
                String orgLevelName = "";
                switch (orgLevel) {
                    case "1":
                        orgLevelName = "总行";
                        break;
                    case "2":
                        orgLevelName = "一级分行";
                        break;
                    case "3":
                        orgLevelName = "二级分行";
                        break;
                    case "4":
                        orgLevelName = "管辖支行";
                        break;
                    default:
                        orgLevelName = "经营性支行";
                }
                organizationDTO.setOrgLevelName(orgLevelName);
                obj[2] = organizationDTO.getOrgLevelName();
                obj[3] = organizationDTO.getOrgId();
                obj[4] = orgType[Integer.parseInt(organizationDTO.getOrgType()) - 1];
                //obj[5] = StringUtil.isNotEmpty(organizationDTO.getOrgRailSwitch()) ? orgRailSwitch[Integer.parseInt(organizationDTO.getOrgRailSwitch())] : null;
                obj[5] = organizationDTO.getOrgRemark();
                return obj;
            }).collect(toList());
            OutputStream out = null;
            // 防止中文乱码
            String headStr = "attachment; filename=\"" + new String(title.getBytes("gb2312"), "ISO8859-1") + "\"";
            response.setContentType("octets/stream");
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.setHeader("Content-Disposition", headStr);
            out = response.getOutputStream();
            ExcelOutput ex = new ExcelOutput(title, headers, dataList);
            ex.export(out);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            HeaderResult.setFailHeader(request, response, e.getMessage());
        }
    }

    /**
     * 下载导入模板xls
     */
    @ApiOperation("下载导入模板xls")
    @PostMapping("/downloadTem")
    public void downloadTem(HttpServletResponse response) {

        String[] headers = new String[]{"机构码", "机构名称", "上级机构码", "机构类型（1-网点、2-金库、3-调拨中心、4-押运公司、5-类金库）",  "备注"};
        List<Object[]> dataList = null;
        // 防止中文乱码
        String headStr = null;
        OutputStream out = null;
        try {
            headStr = "attachment; filename=\"" + new String("customerMangerTemplate.xls".getBytes("utf8"), "ISO8859-1") + "\"";
            response.setContentType("octets/stream");
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.setHeader("Content-Disposition", headStr);
            out = response.getOutputStream();
            ExcelOutput ex = new ExcelOutput("customerMangerTemplate.xls", headers, dataList);
            ex.export(out);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 机构批量导入
     *
     * @param multipartFile addBO
     * @return
     * @throws Exception
     */
    @ApiOperation("导入机构管理信息")
    @PostMapping("/organizationImport")
    public BaseResult importOrganizationInfo(HttpServletRequest request,
                                             @RequestParam("multipartFile") MultipartFile multipartFile) throws Exception {
        try {
            String suffix = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf("."));
            if (".xls".equals(suffix) || ".xlsx".equals(suffix)) {
                InputStream inputStream = multipartFile.getInputStream();
                HSSFWorkbook workbook = new HSSFWorkbook(inputStream);
                HSSFSheet sheet = workbook.getSheetAt(0);
                if (sheet != null) {
                    // getLastCellNum比列标大1,行标&列标都以0开始。
                    System.out.println(sheet.getLastRowNum() + "==============");
                    List<OrganizationAddBO> addBOList = new ArrayList<>();
                    for (int i = 1; i <= sheet.getLastRowNum(); i++) {
                        OrganizationAddBO organizationAddBO = new OrganizationAddBO();
                        // 从第二行开始得到每行的值
                        HSSFRow row = sheet.getRow(i);
                        row.getCell(0).setCellType(CellType.STRING);
                        String orgId = row.getCell(0).getStringCellValue();
                        row.getCell(1).setCellType(CellType.STRING);
                        String orgName = row.getCell(1).getStringCellValue();
                        row.getCell(2).setCellType(CellType.STRING);
                        String orgPid = row.getCell(2).getStringCellValue();
                        row.getCell(3).setCellType(CellType.STRING);
                        String orgtype = row.getCell(3).getStringCellValue();
                        //row.getCell(4).setCellType(CellType.STRING);
                        //String orgrailswitch = row.getCell(4).getStringCellValue();
                        String orgremark = "";
                        if (ObjectUtil.isNotNull(row.getCell(4))) {
                            row.getCell(4).setCellType(CellType.STRING);
                            orgremark = row.getCell(4).getStringCellValue();
                        }
                        //设置默认工作时间
                        OrgWorkingTimeBO orgWorkingTime = new OrgWorkingTimeBO();
                        List<String> list = new ArrayList<>();
                        list.add("1");
                        list.add("2");
                        list.add("3");
                        list.add("4");
                        list.add("5");
                        orgWorkingTime.setDate(list);
                        orgWorkingTime.setStartTime("07:30:00");
                        orgWorkingTime.setEndTime("20:00:00");
                        organizationAddBO.setOrgId(orgId);
                        organizationAddBO.setOrgName(orgName);
                        organizationAddBO.setOrgPid(orgPid);
                        organizationAddBO.setOrgType(orgtype);
                        //organizationAddBO.setOrgRailSwitch(orgrailswitch);
                        organizationAddBO.setOrgRemark(orgremark);
                        organizationAddBO.setOrgWorkingTime(orgWorkingTime);
                        addBOList.add(organizationAddBO);
                    }
                    int flag = 0;
                    String msg = null;
                    String orgId = TokenUtil.getOrgId(request.getHeader("token"));
                    String opId = TokenUtil.getOpId(request.getHeader("token"));
                    String opName = TokenUtil.getOpName(request.getHeader("token"));
                    // 添加机构时需比对操作员机构,只能添加操作员所属机构的下属机构
                    List<String> orgList = getListOrgIds(orgId);
                    orgList.add(orgId);

                    // 操作日志
                    List<SysLog> sysLogList = new ArrayList<>();
                    for (int i = 0; i < addBOList.size(); i++) {
                        try {
                            ValidatorUtils.beanValidate(addBOList.get(i));

                            BaseResult baseResult = organizationService.insertBatchOrganization(
                                    addBOList.get(i), orgId, opId, opName, orgList, sysLogList);

                            if (!"00".equals(baseResult.getDataCode())) {
                                log.info("机构导入错误信息={}", baseResult.getDataMessage());
                                flag++;
                                if (StringUtil.isEmpty(msg)) {
                                    msg = String.valueOf(i + 1);
                                } else {
                                    msg = msg + "," + (i + 1);
                                }
                            }
                        } catch (Exception e) {
                            flag++;
                            if (StringUtil.isEmpty(msg)) {
                                msg = String.valueOf(i + 1);
                            } else {
                                msg = msg + "," + (i + 1);
                            }
                        }
                    }
                    if (sysLogList.size() > 0) {
                        double pro = (double) sysLogList.size() / 500;
                        int index = (int) Math.ceil(pro);
                        for (int i = 0; i < index; i++) {
                            systemLogMapper.insertBatch(
                                    sysLogList.stream().skip(i * 500L).collect(Collectors.toList())
                            );
                        }
                    }
                    if (flag == 0) {
                        return GetResult.getResultSuccess("机构导入成功");
                    } else {
                        return GetResult.getResultFail("第" + msg + "条数据错误，机构导入失败");
                    }

                }
                return GetResult.getResultSuccess("机构导入失败");
            } else {
                return GetResult.getResultFail("文件类型只支持.xls 与.xlsx");
            }

        } catch (IOException e) {
            e.printStackTrace();
            return GetResult.getResultFail("导入失败");
        }


    }

    public List<String> getListOrgIds(String orgId) {
        String strkey = "orgid:" + orgId;
        List<String> lists = null;
        lists = redisUtils.get(strkey, List.class);
        if (lists == null) {
            lists = new ArrayList<>();
            recursiveGetOrgId(lists, orgId);
        }

        return lists;
    }

    //递归查询子机构
    private void recursiveGetOrgId(List<String> lists, String orgId) {
        List<String> orgIdList = organizationMapper.getOrgIdsList(orgId);
        while (orgIdList.isEmpty()) {
            return;
        }
        orgIdList.forEach(childOrgId -> {
            lists.add(childOrgId);
            recursiveGetOrgId(lists, childOrgId);
        });
    }

    /**
     * @param request
     * @return java.lang.String
     * @Author xin.qi
     * @Description 根据用户获取所属机构及下属机构
     * @Date 2020/3/6 9:44
     * @Param
     */
    @RequestMapping(value = "/getOrgIdsByOp", method = RequestMethod.POST)
    @ResponseBody
    @ApiOperation(value = "根据用户获取所属机构下属机构")
    public BaseResult<List<Organization>> getOrganizationIdsByOp(HttpServletRequest request) {
        try {
            return GetResult.getResult(organizationService.getOrganizationIdsByOp(request));
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    @RequestMapping(value = "/getOrgIdsByOrgId", method = RequestMethod.POST)
    @ApiOperation(value = "根据当前机构获取下属机构")
    public BaseResult<List<Organization>> getOrgIdsByOrgId(@RequestBody OrganizationDeleteBO org) {
        try {
            return GetResult.getResult(organizationService.getChildOrgIds(org.getOrgId()));
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    @PostMapping(value = "/configSysPermission")
    @ApiOperation(value = "系统权限配置")
    public BaseResult configSysPermission(HttpServletRequest request, @RequestBody SysPermissionBo sysPermissionBo) {
        try {
            return organizationService.configSysPermission(request, sysPermissionBo);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }

    @PostMapping(value = "/querySysPermission")
    @ApiOperation(value = "获取系统权限配置")
    public BaseResult<SysPermissionDTO> querySysPermission(HttpServletRequest request) {
        try {
            return organizationService.querySysPermission(request);
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            return GetResult.getResultErr();
        }
    }
}
